package client;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

import Gui.CurrentUser;

/**
 * A class which controls the connection with the server.
 * 
 * @author ic08jh7
 * 
 */
public class ConnectionClient {

	private final int port;
	private final String url;
	private SSLSocketFactory sslsocketfactory;
	private SSLSocket sslsocket;
	private InputStream inputstream;
	private InputStreamReader inputstreamreader;
	private BufferedReader bufferedreader;
	private OutputStream outputstream;
	private OutputStreamWriter outputstreamwriter;
	private BufferedWriter bufferedwriter;

	/**
	 * Creates a ssl connection to a server a specific url and a specific port.
	 * 
	 * @param url
	 *            The url to which the connection will be established.
	 * @param port
	 *            The port to use during the connection.
	 */
	public ConnectionClient(String url, int port) {
		this.url = url;
		this.port = port;
	}

	/**
	 * Opens a connection to the server.
	 * 
	 * @return True if the connection was established, else false.
	 */
	public boolean openConnection() {
		try {
			sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();

			sslsocket = (SSLSocket) sslsocketfactory.createSocket(url, port);

			outputstream = sslsocket.getOutputStream();
			outputstreamwriter = new OutputStreamWriter(outputstream);
			bufferedwriter = new BufferedWriter(outputstreamwriter);

			inputstream = sslsocket.getInputStream();
			inputstreamreader = new InputStreamReader(inputstream);
			bufferedreader = new BufferedReader(inputstreamreader);

			sslsocket.addHandshakeCompletedListener(new MyHandshakeListener());
			System.out.println("Start handshake");
			sslsocket.startHandshake();

			return sslsocket.isConnected();

		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * Controls if the client is connected to the server.
	 * 
	 * @return True if the client is connected, else false.
	 */
	public boolean isConnected() {
		return sslsocket.isConnected();
	}

	/**
	 * Sends data to the server. The data has to follow the Johansson-Hallberg
	 * protocol.
	 * 
	 * @param data
	 *            The data to be sent.
	 * @return The server response.
	 */
	public String sendData(String data) {
		try {

			bufferedwriter.write(CurrentUser.instance().getCurrentUserId()
					+ ";" + CurrentUser.instance().getCurrentUserHash()
					+ ";nouncereq;PADDING;" + System.currentTimeMillis()
					+ ";PADDING" + '\n');
			bufferedwriter.flush();

			String nounce = bufferedreader.readLine();
			if (!nounce.equalsIgnoreCase("NACK")) {
				bufferedwriter.write(data + ";" + System.currentTimeMillis()
						+ ";" + nounce + '\n');
				bufferedwriter.flush();

				return bufferedreader.readLine();
			}
			return "NACK";

		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Closes the connection.
	 */
	public void closeConnection() {
		try {
			sslsocket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Listen to when a handshake with the server is completed.
	 * 
	 * @author ic08jh7
	 * 
	 */
	class MyHandshakeListener implements HandshakeCompletedListener {
		public void handshakeCompleted(HandshakeCompletedEvent e) {
			System.out.println("Handshake succesful!");
			System.out.println("Using cipher suite: " + e.getCipherSuite());
		}
	}
}
